package com.cskaoyan.market.controller;

import com.cskaoyan.market.db.domain.MarketAdmin;
import com.cskaoyan.market.service.AdminAuthService;
import com.cskaoyan.market.service.impl.AdminAuthServiceImpl;
import com.cskaoyan.market.util.JacksonUtil;
import com.cskaoyan.market.util.ResponseUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageReader;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.ws.Response;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName AdminAuthController
 * @Description: TODO
 * 数据层需要哪些东西？表已经给大家提供好了
 * 1.创建一个实体类对象和表的字段保持一一对应的关系
 * 2.创建mapper接口----最常见的功能便是增删改查，要去编写基础的增删改查等操作方法
 * 3.创建mapper映射文件----基础的增删改查的sql语句
 * 有没有一种方式可以根据表结构逆向反推出来呢？mybatis逆向工程
 * @Author 远志 zhangsong@cskaoyan.onaliyun.com
 * @Date 2023/6/19 10:00
 * @Version V1.0
 **/
@WebServlet("/admin/auth/*")
public class AdminAuthController extends HttpServlet {

    private AdminAuthService adminAuthService = new AdminAuthServiceImpl();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        String op = requestURI.replace(req.getContextPath() + "/admin/auth/", "");
        if("login".equals(op)){
            login(req, resp);
        }
    }

    /**
     * 登录的业务逻辑：
     * 1.接收用户传递过来的请求参数信息
     * 2.处理具体的业务逻辑：拿着用户名、密码到数据库中进行比对
     * 3.返回结果------只要遵循101公网上的返回值即可
     * 项目中会存在一个问题，叫做CORS错误，叫做跨域问题
     * 跨域问题：只要是访问的页面(localhost:8080)和访问数据(localhost:8083)的主机、端口号不一致，那么便是跨域，浏览器默认阻止该行为
     * 如果希望浏览器允许跨域，则需要服务端返回几个响应头；每次发送请求时，都会有跨域问题，也都需要返回响应头
     * 所以可以将响应头放在filter中
     * @param req
     * @param resp
     */
    private void login(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//        System.out.println("login");
        //1.接收用户传递过来的请求参数信息------抓包
        //获取位于请求体里面的字符串信息-----方案一：字节流
//        ServletInputStream inputStream = req.getInputStream();
//        //构建输出流  ByteArrayOutputStream-----往数组里面写
//        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//        int length = 0;
//        byte[] bytes = new byte[1024];
//        while ((length = inputStream.read(bytes)) != -1){
//            outputStream.write(bytes, 0, length);
//        }
//        String requestBody = outputStream.toString("utf-8");
//        outputStream.close();
//        System.out.println(requestBody);
        //方案二：readline的方式
        BufferedReader reader = req.getReader();
        String requestBody = reader.readLine();
        System.out.println(requestBody);
        //后面的任务暂时先放置 TODO 先着手准备数据层需要的东西
        //需要将json字符串里面的用户名、密码等参数信息接收获取到
        String username = JacksonUtil.parseString(requestBody, "username");
        String password = JacksonUtil.parseString(requestBody, "password");
        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
            //TODO 这里面的状态码定义是0表示成功，除了0之外全部都是失败，但是为了区分是不同的错误原因，定义了不同状态码
            Object o = ResponseUtil.fail(605, "用户名或者密码不能为空");
            resp.getWriter().println(JacksonUtil.writeValueAsString(o));
            return;
        }
        //为什么这里面返回的是一个对象呢？后续该接口要求返回一个avatar头像，这个属性在数据库里面
        MarketAdmin admin = adminAuthService.login(username, password);
        //根据admin是否为null，判断是否登录成功
        //无论成功还是失败，均需要和公网上面的返回值保持一致即可 抓取公网:8083的返回值即可
        if(admin == null){
            //登录失败，用户名或者密码错误 {"errno":605,"errmsg":"用户帐号或密码不正确"}
            Object obj = ResponseUtil.fail(605, "用户名或者密码不对");
            String responseBody = JacksonUtil.writeValueAsString(obj);
            //通过抓包，我们可以发现json字符串需要位于响应体中，那么哪个方法可以设置响应体
            resp.getWriter().println(responseBody);
            return;
        }
        //登录成功
        // {
        //    "errno": 0,
        //    "data": {
        //        "adminInfo": {
        //            "nickName": "admin123",
        //            "avatar": "http://101.43.69.31:8083/wx/storage/fetch/b8cw4hptf8v8ckpz080v.jpg"
        //        },
        //        "token": "0cdfcb03-e50a-451b-9fd2-df56544c4fe6"
        //    },
        //    "errmsg": "成功"
        //}
        //登陆成功的返回值部分需要我们实现的而也就是data的部分
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> adminInfo = new HashMap<>();
        adminInfo.put("nickName", admin.getUsername());
        adminInfo.put("avatar", admin.getAvatar());
        result.put("adminInfo", adminInfo);
        HttpSession session = req.getSession();
        //登录成功之后，将admin信息放入session域
        session.setAttribute("admin", admin);
        //token是一个登录的凭证，这里面直接用session的编号来充当
        String id = session.getId();
        result.put("token", id);
        Object ok = ResponseUtil.ok(result);
        String s = JacksonUtil.writeValueAsString(ok);
        resp.getWriter().println(s);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        String op = requestURI.replace(req.getContextPath() + "/admin/auth/", "");
        if("info".equals(op)){
            info(req, resp);
        }
    }

    /**
     * info个人信息接口，要求返回管理员的个人信息，里面需要有用户名、头像
     * 这些数据实际上在登录接口中已经获取到了，所以没必要再去去获取
     * 可以实际和login进行共享数据----选择session域
     * {
     *     "errno": 0,
     *     "data": {
     *         "roles": [
     *             "超级管理员"
     *         ],
     *         "name": "admin123",
     *         "perms": [
     *             "*"
     *         ],
     *         "avatar": "http://101.43.69.31:8083/wx/storage/fetch/b8cw4hptf8v8ckpz080v.jpg"
     *     },
     *     "errmsg": "成功"
     * }
     * @param req
     * @param resp
     */
    private void info(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //在当前servlet中，从session域中再次获取admin信息
        HttpSession session = req.getSession();
        //获取登录时，放入session域里面的数据
        MarketAdmin admin = (MarketAdmin) session.getAttribute("admin");
        //roles 角色（涉及到权限，项目一不用去写） perms 权限 项目一不用去写
        Map<String, Object> result = new HashMap<>();
        result.put("roles", new String[]{"超级管理员"});
        result.put("name", admin.getUsername());
        result.put("perms", new String[]{"*"});
        result.put("avatar", admin.getAvatar());
        Object ok = ResponseUtil.ok(result);
        String s = JacksonUtil.writeValueAsString(ok);
        resp.getWriter().println(s);
    }
}
